%% @author Rain
%% @doc 网络接收


-module(net_acceptor_svr).
-behaviour(gen_server).

-include("net.hrl").
-include("global.hrl").

-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

%% ====================================================================
%% API functions
%% ====================================================================
-export([start_link/1]).



%% ====================================================================
%% Behavioural functions
%% ====================================================================
-record(state, {lsocket = undefined,
				link_cnt = 0
				}).

%% init/1
%% ====================================================================
%% @doc <a href="http://www.erlang.org/doc/man/gen_server.html#Module:init-1">gen_server:init/1</a>
-spec init(Args :: term()) -> Result when
	Result :: {ok, State}
			| {ok, State, Timeout}
			| {ok, State, hibernate}
			| {stop, Reason :: term()}
			| ignore,
	State :: term(),
	Timeout :: non_neg_integer() | infinity.
%% ====================================================================
init(Port) ->
	start_listen(Port),
    {ok, #state{}}.


%% handle_call/3
%% ====================================================================
%% @doc <a href="http://www.erlang.org/doc/man/gen_server.html#Module:handle_call-3">gen_server:handle_call/3</a>
-spec handle_call(Request :: term(), From :: {pid(), Tag :: term()}, State :: term()) -> Result when
	Result :: {reply, Reply, NewState}
			| {reply, Reply, NewState, Timeout}
			| {reply, Reply, NewState, hibernate}
			| {noreply, NewState}
			| {noreply, NewState, Timeout}
			| {noreply, NewState, hibernate}
			| {stop, Reason, Reply, NewState}
			| {stop, Reason, NewState},
	Reply :: term(),
	NewState :: term(),
	Timeout :: non_neg_integer() | infinity,
	Reason :: term().
%% ====================================================================
handle_call(Request, From, State) ->
    Reply = ok,
    {reply, Reply, State}.


%% handle_cast/2
%% ====================================================================
%% @doc <a href="http://www.erlang.org/doc/man/gen_server.html#Module:handle_cast-2">gen_server:handle_cast/2</a>
-spec handle_cast(Request :: term(), State :: term()) -> Result when
	Result :: {noreply, NewState}
			| {noreply, NewState, Timeout}
			| {noreply, NewState, hibernate}
			| {stop, Reason :: term(), NewState},
	NewState :: term(),
	Timeout :: non_neg_integer() | infinity.
%% ====================================================================
handle_cast(Msg, State) ->
    {noreply, State}.


%% handle_info/2
%% ====================================================================
%% @doc <a href="http://www.erlang.org/doc/man/gen_server.html#Module:handle_info-2">gen_server:handle_info/2</a>
-spec handle_info(Info :: timeout | term(), State :: term()) -> Result when
	Result :: {noreply, NewState}
			| {noreply, NewState, Timeout}
			| {noreply, NewState, hibernate}
			| {stop, Reason :: term(), NewState},
	NewState :: term(),
	Timeout :: non_neg_integer() | infinity.
%% ====================================================================


handle_info({start_listen, Port}, State) ->
	State1 = do_start_listen(Port, State),
	{noreply, State1};

handle_info(start_accept, #state{lsocket = LSock, link_cnt = LinkCnt} = State) ->
	case do_start_accept(LSock) of
		ok ->
			State1 = State#state{link_cnt = LinkCnt + 1};
		_ ->
			State1 = State
	end,
	self() ! start_accept,
	{noreply, State1};

handle_info(Info, State) ->
    {noreply, State}.


%% terminate/2
%% ====================================================================
%% @doc <a href="http://www.erlang.org/doc/man/gen_server.html#Module:terminate-2">gen_server:terminate/2</a>
-spec terminate(Reason, State :: term()) -> Any :: term() when
	Reason :: normal
			| shutdown
			| {shutdown, term()}
			| term().
%% ====================================================================
terminate(Reason, State) ->
    ok.


%% code_change/3
%% ====================================================================
%% @doc <a href="http://www.erlang.org/doc/man/gen_server.html#Module:code_change-3">gen_server:code_change/3</a>
-spec code_change(OldVsn, State :: term(), Extra :: term()) -> Result when
	Result :: {ok, NewState :: term()} | {error, Reason :: term()},
	OldVsn :: Vsn | {down, Vsn},
	Vsn :: term().
%% ====================================================================
code_change(OldVsn, State, Extra) ->
    {ok, State}.


%% ====================================================================
%% Internal functions
%% ====================================================================

%% @doc 开启监听
start_listen(Port) ->
	self() ! {start_listen, Port}.
	
	
do_start_listen(Port, State) ->	
	case gen_tcp:listen(Port, []) of
		{ok, LSock} ->
			self() ! start_accept,
			State#state{lsocket = LSock};
		{error, Reason} ->
			io:format("Listen Fail Reason = ~p~n",[Reason]),
			State
	end.

%% @doc 接收Socket
%% Retrun: ok | {error, Reason}
do_start_accept(LSock) ->
	case gen_tcp:accept(LSock) of
		{ok, Sock} ->
			start_user(Sock),
			ok;
		{error, Reason} ->
			io:format("Accept Fail Reason = ~p~n",[Reason]),
			{error, Reason}
	end.

%% @doc 根据	Socket分配用户进程
start_user(Sock) ->
	case user_svr:start_link() of 
		{ok, UserSvrPid} ->
			case net_router_svr:start_link(Sock, UserSvrPid) of 
				{ok, RouterPid} ->
					UserSvrPid ! {bind_router, RouterPid},
					case net_reader_svr:start_link(Sock, RouterPid) of
						{ok, ReaderPid} -> %% 将接收进程设置为Reader进程
							gen_tcp:controlling_process(Sock, ReaderPid),
							io:format("Net User Add ~p~n",[Sock]);
						{error, Reason} ->
							io:format("Start Reader Fail Reason = ~p~n",[Reason]);
						_ ->
							io:format("Start Reader Ignore~n",[])
					end;
				{error, Reason} ->
							io:format("Start Router Fail Reason = ~p~n",[Reason]);
						_ ->
							io:format("Start Router Ignore~n",[])
			end;
		{error, Reason} ->
			io:format("Start UserSvr Fail Reason = ~p~n",[Reason]);
		_ ->
			io:format("Start UserSvr Ignore~n",[])
	end.
			
	
%% @doc 启动接收器进程
start_link(Port) ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, Port, [{timeout, ?START_LINK_TIME_OUT}]).			

